package x.ovo.wechat.bot.plugin;

import lombok.Setter;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.dromara.hutool.core.io.file.FileUtil;
import org.dromara.hutool.core.text.StrUtil;
import org.dromara.hutool.http.client.HttpDownloader;
import org.dromara.hutool.http.meta.ContentType;
import org.dromara.hutool.http.multipart.UploadFile;
import org.dromara.hutool.http.server.action.Action;
import org.dromara.hutool.http.server.filter.HttpFilter;
import org.dromara.hutool.json.JSONObject;
import org.dromara.hutool.json.JSONUtil;
import x.ovo.wechat.bot.core.contact.RetrievalType;
import x.ovo.wechat.bot.core.entity.Contact;
import x.ovo.wechat.bot.core.entity.Member;
import x.ovo.wechat.bot.core.enums.ContactType;
import x.ovo.wechat.bot.core.plugin.Plugin;

import java.io.File;
import java.util.Objects;

@SuppressWarnings("DuplicatedCode")
@UtilityClass
@Slf4j(topic = "HttpHelper")
public class HttpHelper {

    @Setter
    private static Plugin plugin;

    public static Action helpAction() {
        return (req, res) -> res.write("""
                Http Server 接口说明
                
                server启动后，请求需要添加token进行鉴权，token可在配置文件中自行配置，若无配置会自动生成并打印日志。
                接收消息需要一个webhook地址，需在配置文件中进行配置，事件监听器监听所有消息事件并将消息以POST请求发送到该地址。
                
                1、发送文本消息 [POST - sendText] ContentType: application/json
                参数：
                    target: 接收消息的联系人
                    type: target类型 [NICK_NAME|USER_NAME|REMARK_NAME]
                    message: 发送的消息正文
                2、发送图片消息 [POST - sendImage] ContentType: form-data
                参数：
                    target: 接收消息的联系人
                    type: target类型 [NICK_NAME|USER_NAME|REMARK_NAME]
                    file|url: 发送的图片文件或连接
                3、发送视频消息 [POST - sendVideo] ContentType: form-data
                参数：
                    target: 接收消息的联系人
                    type: target类型 [NICK_NAME|USER_NAME|REMARK_NAME]
                    file|url: 发送的视频文件或连接
                4、发送文件消息 [POST - sendFile] ContentType: form-data
                参数：
                    target: 接收消息的联系人
                    type: target类型 [NICK_NAME|USER_NAME|REMARK_NAME]
                    file|url: 发送的文件或连接
                5、获取bot信息 [GET - getSelf]
                参数：无
                6、获取联系人信息 [GET - getContact]
                参数：
                    target: 需要获取的联系人
                    type: target类型 [NICK_NAME|USER_NAME|REMARK_NAME]
                7、获取群组成员信息 [GET - getContact]
                参数：
                    group: 群组名称
                    target: 需要获取的群组成员
                    type: target类型 [NICK_NAME|USER_NAME|REMARK_NAME]
                8、修改群组名称 [GET - getContact]
                参数：
                    group: 群组名称
                    newName: 新群组名称
                """, ContentType.TEXT_PLAIN.getValue());
    }

    public static HttpFilter tokenFilter(String serverToken) {
        return (req, res, chain) -> {
            String token = req.getParam("token");
            if (StrUtil.equals(serverToken, token)) {
                chain.doFilter(req.getHttpExchange());
            } else {
                res.write("token错误，无法访问", ContentType.TEXT_PLAIN.getValue());
            }
        };
    }

    /**
     * 发送文本消息
     *
     * @return {@link Action }
     */
    public static Action sendTextAction() {
        return (req, res) -> {
            if (!req.isPostMethod()) res.write("请使用post请求");
            JSONObject body = JSONUtil.parseObj(req.getBody());
            String target = body.getStr("target");
            String type = body.getStr("type");
            Contact contact = plugin.getContext().getContactManager().get(target, RetrievalType.valueOf(type));
            boolean b = contact.sendMessage(body.getStr("message"));
            res.write(b ? "success" : "failure", ContentType.TEXT_PLAIN.getValue());
            log.debug("发送文本消息到 [{}]，状态: {}", target, b);
        };
    }

    /**
     * 发送图像操作
     *
     * @return {@link Action }
     */
    public static Action sendImageAction() {
        return (req, res) -> {
            if (!req.isPostMethod()) res.write("请使用post请求");
            File file = null;
            try {
                String url = req.getMultipart().getParam("url");
                if (StrUtil.isNotBlank(url)) {
                    file = FileUtil.file(plugin.getDataDir(), StrUtil.subAfter(url, '/', true));
                    HttpDownloader.downloadFile(url, file);
                } else {
                    UploadFile uploadFile = req.getMultipart().getFile("file");
                    file = FileUtil.file(plugin.getDataDir(), uploadFile.getFileName());
                    uploadFile.write(file);
                }

                String target = req.getMultipart().getParam("target");
                String type = req.getMultipart().getParam("type");
                Contact contact = plugin.getContext().getContactManager().get(target, RetrievalType.valueOf(type));
                boolean b = contact.sendImage(file);
                res.write(b ? "success" : "failure", ContentType.TEXT_PLAIN.getValue());
                log.debug("发送图片消息到 [{}]，状态: {}", target, b);
            } finally {
                if (Objects.nonNull(file)) {
                    FileUtil.del(file);
                }
            }
        };
    }

    /**
     * 发送视频操作
     *
     * @return {@link Action }
     */
    public static Action sendVideoAction() {
        return (req, res) -> {
            if (!req.isPostMethod()) res.write("请使用post请求");

            File file = null;
            try {
                String url = req.getMultipart().getParam("url");
                if (StrUtil.isNotBlank(url)) {
                    file = FileUtil.file(plugin.getDataDir(), StrUtil.subAfter(url, '/', true));
                    HttpDownloader.downloadFile(url, file);
                } else {
                    UploadFile uploadFile = req.getMultipart().getFile("file");
                    file = FileUtil.file(plugin.getDataDir(), uploadFile.getFileName());
                    uploadFile.write(file);
                }

                String target = req.getMultipart().getParam("target");
                String type = req.getMultipart().getParam("type");
                Contact contact = plugin.getContext().getContactManager().get(target, RetrievalType.valueOf(type));
                boolean b = contact.sendVideo(file);
                res.write(b ? "success" : "failure", ContentType.TEXT_PLAIN.getValue());
                log.debug("发送视频消息到 [{}]，状态: {}", target, b);
            } finally {
                if (Objects.nonNull(file)) {
                    FileUtil.del(file);
                }
            }
        };
    }

    /**
     * 发送文件操作
     *
     * @return {@link Action }
     */
    public static Action sendFileAction() {
        return (req, res) -> {
            if (!req.isPostMethod()) res.write("请使用post请求");
            File file = null;
            try {
                String url = req.getMultipart().getParam("url");
                if (StrUtil.isNotBlank(url)) {
                    file = FileUtil.file(plugin.getDataDir(), StrUtil.subAfter(url, '/', true));
                    HttpDownloader.downloadFile(url, file);
                } else {
                    UploadFile uploadFile = req.getMultipart().getFile("file");
                    file = FileUtil.file(plugin.getDataDir(), uploadFile.getFileName());
                    uploadFile.write(file);
                }

                String target = req.getMultipart().getParam("target");
                String type = req.getMultipart().getParam("type");
                Contact contact = plugin.getContext().getContactManager().get(target, RetrievalType.valueOf(type));
                boolean b = contact.sendFile(file);
                res.write(b ? "success" : "failure", ContentType.TEXT_PLAIN.getValue());
                log.debug("发送文件消息到 [{}]，状态: {}", target, b);
            } finally {
                if (Objects.nonNull(file)) {
                    FileUtil.del(file);
                }
            }
        };
    }

    /**
     * 获取联系人操作
     *
     * @return {@link Action }
     */
    public static Action getContactAction() {
        return (req, res) -> {
            String target = req.getParam("target");
            String type = req.getParam("type");
            Contact contact = plugin.getContext().getContactManager().get(target, RetrievalType.valueOf(type));
            if (Objects.nonNull(contact)) {
                res.write(JSONUtil.toJsonStr(contact));
                log.debug("获取联系人信息成功: {}", target);
            } else {
                res.write("未找到联系人信息", ContentType.TEXT_PLAIN.getValue());
                log.warn("未找到联系人信息: {}", target);
            }
        };
    }

    public static Action getSelfAction() {
        return (req, res) -> {
            try {
                res.write(JSONUtil.toJsonStr(plugin.getContext().getSession().getContact()), ContentType.TEXT_PLAIN.getValue());
            } catch (Exception e) {
                res.write("获取个人信息失败", ContentType.TEXT_PLAIN.getValue());
            }
        };
    }

    /**
     * 获取组成员操作
     *
     * @return {@link Action }
     */
    public static Action getGroupMemberAction() {
        return (req, res) -> {
            String group = req.getParam("group");
            String target = req.getParam("target");
            String type = req.getParam("type");
            Contact contact = plugin.getContext().getContactManager().get(group, RetrievalType.NICK_NAME);
            if (Objects.isNull(contact) || !ContactType.GROUP.equals(contact.getType())) {
                res.write("未找到群信息", ContentType.TEXT_PLAIN.getValue());
                log.warn("未找到群信息: {}", group);
                return;
            }
            Member member = plugin.getContext().getContactManager().get(contact.getUserName(), target, RetrievalType.valueOf(type));
            if (Objects.nonNull(member)) {
                res.write(JSONUtil.toJsonStr(member));
                log.debug("获取群成员信息: {}-{}", group, target);
            } else {
                res.write("未找到群成员信息", ContentType.TEXT_PLAIN.getValue());
                log.warn("未找到群成员信息: {}-{}", group, target);
            }
        };
    }

    /**
     * 修改组名称操作
     *
     * @return {@link Action }
     */
    public static Action modifyGroupNameAction() {
        return (req, res) -> {
            String group = req.getParam("group"), newName = req.getParam("newName");
            boolean b = plugin.getContext().getApi().modifyGroupName(group, newName);
            res.write(StrUtil.format("修改群名 {}", b ? "成功" : "失败"), ContentType.TEXT_PLAIN.getValue());
            log.debug("修改群名: {}-{}", group, newName);
        };
    }
}
